package testdatagenerator;

import Storage.DBConnect;
import java.awt.*;
import java.awt.event.*;
import java.util.Calendar;
import java.util.Random;
import java.util.Vector;

import javax.swing.*;


//please note this code may not be submitted to thedailywtf.com as it was created by an
//undergraduate student. I apologize that it did not turn out as pretty as I envisioned
public class NodeFrame extends JFrame {
	private static final long serialVersionUID = 1L;
	private Random gen;
	private Attack[] theAttacks;
	private JComboBox SelectAttack, whichGrid;
	private GeneralData theData;
	private JButton Edit, Ok, detectAttacks;
	private JLabel PerRowL;
	private JTextField NumAttacks, NumNodes, PerRow, Avg, ttl, Dev, Trans, DropRate, Vtime;
        private JRadioButton dbConnection = new JRadioButton("Database Disconnected",false);
        private JRadioButton flooding = new JRadioButton("Flooding",false);
        private JRadioButton replay = new JRadioButton("Replay",false);
        private JRadioButton selectiveForwarding = new JRadioButton("Selective Forwarding",false);
        private JEditorPane resultsPane = new JEditorPane();
        private JScrollPane resultsScrollPane = new JScrollPane(resultsPane);
        private JEditorPane attackResultsPane = new JEditorPane();
        private JScrollPane attackResultsScrollPane = new JScrollPane(attackResultsPane);
        private JProgressBar progressBar = new JProgressBar(0,100);
        private JTextArea taskOutput = new JTextArea(5, 20);
        private JScrollPane progressScrollPane = new JScrollPane(taskOutput);
        private attackDetection2.WSNetwork attacks = new attackDetection2.WSNetwork();
        
	public NodeFrame(){     
		super("Please Set Up The Simulation Parameters");
		gen = new Random();
		setLayout(new GridLayout(2, 2));
		setResizable(false);
		Ok = new JButton("Generate and export data");
		Trans = new JTextField();
		JLabel VtimeL = new JLabel("Valid time:");
		JLabel TransL = new JLabel("Transmissions:");
		JLabel NumAttacksL = new JLabel("Number of attacks:");
		JLabel DropRateL = new JLabel("Packet drop rate:");
		PerRowL = new JLabel("Nodes per row:");
		JLabel SelectAttackL = new JLabel("Select attack:");
		JLabel AvgL = new JLabel("Mean delay:");
		JLabel ttlL = new JLabel("Time to live:");
		JLabel DevL = new JLabel("Std dev. of delay:");
		JLabel NumNodesL = new JLabel("Number of nodes:");
		whichGrid = new JComboBox();
		whichGrid.addItem("Grid graph");
		whichGrid.addItem("Rand graph");
		whichGrid.setSelectedIndex(0);
		ActionListener whichGridL = new ActionListener(){
			public void actionPerformed(ActionEvent arg0) {
				if (whichGrid.getSelectedIndex()==0){
					PerRowL.setText("Nodes per row:");
					PerRow.setText("5");
				} else {
					PerRowL.setText("Graph density:");
					try {
						PerRow.setText(((Integer)(2*Integer.parseInt(NumNodes.getText()))).toString());
					} catch(Exception exc){
						PerRow.setText("5");
					}
				}
			}
		};
		whichGrid.addActionListener(whichGridL);
		Edit = new JButton("Edit");
		Vtime = new JTextField();
		theData = GeneralData.getGeneralData();
		setSize(1200, 600);
		NumNodes = new JTextField();
		SelectAttack = new JComboBox();
		PerRow = new JTextField();
		NumAttacks = new JTextField();
		DropRate = new JTextField();
		Avg = new JTextField();
		ttl = new JTextField();
		Dev = new JTextField();
		NumNodes.setText("20");
		NumAttacks.setText("1");
		PerRow.setText("5");
		Trans.setText("400");
		DropRate.setText("0");
		Vtime.setPreferredSize(new Dimension(50, 20));
		DropRate.setPreferredSize(new Dimension(50, 20));
		NumNodes.setPreferredSize(new Dimension(50, 20));
		Avg.setPreferredSize(new Dimension(50, 20));
		ttl.setPreferredSize(new Dimension(50, 20));
		Dev.setPreferredSize(new Dimension(50, 20));
		PerRow.setPreferredSize(new Dimension(50, 20));
		Trans.setPreferredSize(new Dimension(50, 20));
		NumAttacks.setPreferredSize(new Dimension(50, 20));
		ActionListener EditL = new ActionListener(){
			public void actionPerformed(ActionEvent arg0) {
				try {
					theData.setNodes(Integer.parseInt(NumNodes.getText()));
					EditFrame n = new EditFrame(theAttacks[SelectAttack.getSelectedIndex()], theData);
					n.setVisible(true);
				} catch(Exception exc) {
					JOptionPane.showMessageDialog(null, "Please select a valid Attack-id of the node you would like to edit.", "Error!",JOptionPane.ERROR_MESSAGE);
				}
			}
		};
		this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
		Edit.addActionListener(EditL);
		ActionListener NumAttacksAL = new ActionListener(){
			public void actionPerformed(ActionEvent arg0) {
				recalcNumAttacks();
			}
		};
		FocusListener NumAttacksFL = new FocusListener(){
			public void focusGained(FocusEvent arg0) {}
			public void focusLost(FocusEvent arg0) {
				recalcNumAttacks();
			}
		};
		ActionListener OkayL = new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				try {
                                        
					theData.setMean(Avg.getText());
					theData.setNodes(NumNodes.getText());
					theData.setPerRow(PerRow.getText(), whichGrid.getSelectedIndex()==0);
					theData.setTTL(ttl.getText());
					theData.setStdDev(Dev.getText());
					theData.setTrans(Trans.getText());
					theData.setDropRate(DropRate.getText());
					theData.setNumAttacks(NumAttacks.getText());
					theData.setValidTime(Vtime.getText());
                                        taskOutput.append("Making Nodes\n");
					makeNodes();
                                        taskOutput.append("Generating Graph\n");
					if (whichGrid.getSelectedIndex()==0){
						generateGridGraph();
					} else {	
						generateRandomGraph();
					}
                                        taskOutput.append("Creating attacks\n");
					createAttacks();
                                        taskOutput.append("Displaying attack Members\n");
					displayAttacks();
                                        taskOutput.append("Setting up attacks\n");
					giveNodesAttackDat();
                                        taskOutput.append("Simulating network\n");
                                        resultsPane.setText(simulateNetwork(progressBar));
                                        taskOutput.append("Simulation done\n");
					//dispose();
					//System.exit(0);
				} catch(FieldException exc){
					Node.deleteAllNodes();
					JOptionPane.showMessageDialog(null, "Your entry for the field \""+exc.getField()+"\" does not make sense.", "Error!",JOptionPane.ERROR_MESSAGE);
				} catch(Exception exc){
					Node.deleteAllNodes();
				}
			}	
		};
		Ok.addActionListener(OkayL);
		NumAttacks.addActionListener(NumAttacksAL);
		NumAttacks.addFocusListener(NumAttacksFL);
		Avg.setText("3");
		ttl.setText("10");
		Dev.setText(".1");
		Vtime.setText("180");
                this.setLayout(new FlowLayout(FlowLayout.CENTER));
		JPanel panel1 = new JPanel(), panel2 = new JPanel();
                JPanel statusPane = new JPanel(), progressPane = new JPanel();
                JPanel attackDetectionPane = new JPanel();
		panel1.setLayout(new FlowLayout(0,10,10));
		panel1.add(NumNodesL);
		panel1.add(NumNodes);
		panel1.add(whichGrid);
		panel1.add(PerRowL);
		panel1.add(PerRow);
		panel1.add(DropRateL);
		panel1.add(DropRate);
		panel1.add(NumAttacksL);
		panel1.add(NumAttacks);
		panel1.add(SelectAttackL);
		panel1.add(SelectAttack);
		panel1.add(Edit);
		add(panel1);
		panel2.add(TransL);
		panel2.add(Trans);
		panel2.add(AvgL);
		panel2.add(Avg);
		panel2.add(DevL);
		panel2.add(Dev);
		panel2.add(ttlL);
		panel2.add(ttl);
		panel2.add(VtimeL);
		panel2.add(Vtime);
		panel2.add(Ok);
		add(panel2);
		recalcNumAttacks();
                
               /* My Stuff */
                dbConnection.setEnabled(false);
                if ( new Storage.DBConnect().connectToDatabase()){
                    dbConnection.setSelected(true);
                    dbConnection.setText("Database Connected");
                }

                JLabel sampleDataLabel = new JLabel("Generated Data");
                JLabel generatorStatusLabel = new JLabel("Data Generation Progress");
                JLabel attackDetectionLabel = new JLabel("Attack Detection Section");
                JLabel attackResultsLabel = new JLabel("Attack Detection Results");
                JLabel databaseInfo = new JLabel("Database Info");

                detectAttacks = new JButton("Start Attack Detection");

                taskOutput.setMargin(new Insets(5,5,5,5));
                taskOutput.setEditable(false);
                statusPane.add(databaseInfo);
                statusPane.add(dbConnection);
                
                resultsPane.setEditable(false);
                resultsScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
                resultsScrollPane.setPreferredSize(new Dimension(500, 145));
                resultsScrollPane.setMinimumSize(new Dimension(10, 10));
                statusPane.add(sampleDataLabel);
                statusPane.add(resultsScrollPane);
                //statusPane.setLayout(new FlowLayout(FlowLayout.CENTER));
                statusPane.setLayout(new BoxLayout(statusPane, BoxLayout.PAGE_AXIS));
                statusPane.setBorder(BorderFactory.createLineBorder(Color.black));
                add(statusPane);
                
                
                progressBar.setValue(0);
                progressBar.setStringPainted(true);
                progressPane.add(generatorStatusLabel);
                progressPane.add(progressBar);
                
                progressScrollPane.setPreferredSize(new Dimension(200,150));
                
                progressPane.add(progressScrollPane);
                
                progressPane.setLayout(new BoxLayout(progressPane, BoxLayout.PAGE_AXIS));
                progressPane.setBorder(BorderFactory.createLineBorder(Color.black));
                add(progressPane);

                flooding.setEnabled(false);
                replay.setEnabled(false);
                selectiveForwarding.setEnabled(false);

                attackResultsPane.setEditable(false);
                
                attackResultsScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
                attackResultsScrollPane.setPreferredSize(new Dimension(500, 145));
                attackResultsScrollPane.setMinimumSize(new Dimension(10, 10));

                attackDetectionPane.add(attackDetectionLabel);
                attackDetectionPane.add(detectAttacks);
                attackDetectionPane.add(flooding);
                attackDetectionPane.add(replay);
                attackDetectionPane.add(selectiveForwarding);
                attackDetectionPane.add(attackResultsLabel);
                attackDetectionPane.add(attackResultsScrollPane);
                attackDetectionPane.setLayout(new BoxLayout(attackDetectionPane, BoxLayout.PAGE_AXIS));


                switch(attacks.checkAttacks().toLowerCase().charAt(0)) {
                    case 'r':
                        flooding.setSelected(true);
                        flooding.setText("Flooding Attack Detected!");
                        break; // replay
                    case 'f':
                        replay.setSelected(true);
                        replay.setText("Replay Attack Detected!");
                        break; // flooding
                    case 's':
                        selectiveForwarding.setSelected(true);
                        selectiveForwarding.setText("Selective Forwarding Detected!");
                        break; // selective Forwarding
                    default: break;
                }

                //attackDetectionPane.setLayout(new FlowLayout(FlowLayout.CENTER));
                attackDetectionPane.setBorder(BorderFactory.createLineBorder(Color.black));
                add(attackDetectionPane);
                
	}
	
	//Create any attacks that were indicated that they should be randomly chosen
	public void createAttacks(){
		for (int i=0;i<theAttacks.length;i++){
			if (theAttacks[i] != null){
		//Any attacks that were instructed not to choose their members randomly will
		//do nothing when this function is run, others will pick random connected nodes
		//and make those its member		
				theAttacks[i].pickMembers();
			}	
		}
	}
	
	public void displayAttacks(){
		for (int i=0;i<theAttacks.length;i++){
			if (theAttacks[i] != null){
		//Any attacks that were instructed to choose their members randomly will
		//display what members they picked. All others will do nothing.	
				theAttacks[i].displayMembers("Attack"+((Integer)i).toString());
			}	
		}
	}
	
	public void makeNodes(){
		int numNodes = theData.getNodes();
		for(int i=0;i<numNodes;i++){
			new Node(i, theData.getMean(), theData.getStdDev(), theData.getDropRate());
		}
	}
	
	public void generateGridGraph(){
		int loop2, i, j;
		Node node1, node2, node3;
		int perRow = theData.getPerRow(), numNodes = theData.getNodes();
		int rows = GeneralMethods.ceil((((double) numNodes)/perRow));
		for(i=0;i<rows;i++){
			if (numNodes-i*perRow<perRow){
				loop2 = numNodes-i*perRow;
			} else {
				loop2 = perRow;
			}
			for(j=0;j<loop2-1;j++){
				node1 = Node.getNodeById(i*perRow+j);
				node2 = Node.getNodeById(i*perRow+j+1);
				node1.makeNeighbors(node2);
				//don't establish downward connection on bottom row
				if (i!=0){
					node3 = Node.getNodeById((i-1)*perRow+j);
					node1.makeNeighbors(node3);
				}	
			}
			//don't establish downward connection on bottom row
			if (i!=0) {
				node1 = Node.getNodeById(i*perRow+j);
				node2 = Node.getNodeById((i-1)*perRow+j);
				node1.makeNeighbors(node2);
			}	
		}
	}
	
	private void generateRandomGraph() throws Exception{
		int numNodes = Node.getNumNodes();
		int connections = theData.getPerRow();
		Vector<Node> Nodes = new Vector<Node>();
		if (connections >= numNodes*(numNodes-1)/2){
			JOptionPane.showMessageDialog(null, "It is impossible to have a graph that size with that many nonredudant connections.", "Error!",JOptionPane.ERROR_MESSAGE);
			throw new Exception();
		}
		if (connections < Node.getNumNodes()-1){
			JOptionPane.showMessageDialog(null, "It is impossible to have a connected graph with so few connections.", "Error!",JOptionPane.ERROR_MESSAGE);
			throw new Exception();
		}
		connections = connections-Node.getNumNodes()+1;
		for(int i=0;i<Node.getNumNodes();i++){
			Nodes.add(Node.getNodeById(i));
		}
		Node temp1 = Nodes.remove(gen.nextInt(Nodes.size())), temp2;
		while(Nodes.size() > 0){
			temp2 = Nodes.remove(gen.nextInt(Nodes.size()));
			temp1.makeNeighbors(temp2);
			temp1 = temp2;
		}
		Node node1, node2;
		while(connections>0){
			node1 = Node.getRandom();
			node2 = node1.pickRandomNonNeighbor();
			if (node2==null){
				continue;
			}
			node1.makeNeighbors(node2);
			connections--;
		}
	}
	
	private String simulateNetwork(JProgressBar progressBar){
            int i = 1;
		Calendar time = Calendar.getInstance();
		int TTL = theData.getTTL();
		double vtime = theData.getVtime();
		Attack[] attacks = createAttackArray();
		double[] weights = getWeightArray(attacks);
		GiantString.getGiantString().Start();
                while(theData.getTrans()>0){
                        i++;
                        progressBar.setValue(i);
			Node origin = Node.getNodeById(selectOrigin(attacks, weights));
			packet toBeSent = new packet(selectDest(origin.getId()), TTL, time, vtime);
			origin.givePacket(toBeSent);
			origin.send(theData);
			time = toBeSent.getTime();
			time.add(Calendar.MILLISECOND, gen.nextInt(100));
		}
		//System.out.println(packet.getStdDev());
		GiantString.getGiantString().Finish();
		return Node.printRelevantNodeData();
	}
	
	private void giveNodesAttackDat(){
		for(int i=0;i<theAttacks.length;i++){
			Vector<Node> members = theAttacks[i].getMembers();
			for (int j=0;j<members.size();j++){
				members.get(j).setMeanIfGreater(theAttacks[i].getMean());
				members.get(j).setDevIfGreater(theAttacks[i].getStdDev());
				members.get(j).setDropRateIfGreater(theAttacks[i].getDropRate());
				members.get(j).setAttack();
			}
		}
	}
	
	private double[] getWeightArray(Attack[] attacks){
		double[] ret = new double[attacks.length];
		for(int i=0;i<attacks.length;i++){
			ret[i] = attacks[i].getFreq();
		}
		return ret;
	}
	
	private int selectDest(int origin){
		int max = 0, res = origin;
		if (Node.getNumNodes() > 0) {
			while(res==origin){
				max = Node.getNumNodes()-1;
				res = gen.nextInt(max);
			}
		}	
		return res;
	}
	
	private int selectOrigin(Attack[] attacks, double[] weights){
		int i;
		double sum = 0;
		//determine which attack to use which includes the "normal" attack
		//please note: the "normal" attack doesn't actually attack.
		for(i=0;i<weights.length;i++){
			sum += weights[i];
		}
		double choice = gen.nextDouble(), curr = 0;
		for(i=0;curr/sum < choice;i++){
			curr += weights[i];
		}
		//determine which node in that attack to use
		Attack choosen = attacks[i-1];
		return choosen.getRandomMemberId(); 
	}
	
	private Attack[] createAttackArray(){
		boolean normNode;
		int normWeight = 0, i;
		//put all nodes not already in an attack into "normal" attack.
		//please note: the "normal" attack doesn't actually attack.
		Attack normNodes = new Attack();
		for(int j=0;j<theData.getNodes();j++){
			normNode = true;
			for(i=0;i<theAttacks.length;i++){
				normNode = normNode && !theAttacks[i].contains(j);
			}
			if (normNode) {
				normNodes.addAttack(j);
				normWeight++;
			}
		}
		normNodes.setMean(theData.getMean());
		normNodes.setStdDev(theData.getStdDev());
		normNodes.setFreq(normWeight);
		//add "normal" attack into the array of attacks
		Attack[] attacks = new Attack[theAttacks.length+1];
		for(i=0;i<theAttacks.length;i++){
			attacks[i] = theAttacks[i];
		}
		attacks[i] = normNodes;
		return attacks;
	}
	
	private void recalcNumAttacks(){
		int temp = 0;
		try {
			temp = Integer.parseInt(NumAttacks.getText());
		} catch(Exception e){
			temp = 0;
		}
		if (temp < 0){
			temp = 0;
		}
		try {
			theData.setNumAttacks(temp);
		} catch(Exception exc){}	
		SelectAttack.removeAllItems();
		for(int i=0;i<temp;i++){
			SelectAttack.addItem(((Integer)i).toString());
		}
		SelectAttack.updateUI();
		if (temp!=0){
			theAttacks = new Attack[temp];
			for(int i=0;i<temp;i++){
				theAttacks[i] = new Attack();
			}
		}
	}
}
